using System;
using System.Collections.Generic;
using System.Text;
using Xeml.Sampling.Contracts;
using Mpi.Common.Collections;
using Xeml.Document.Contracts;
using System.Collections.ObjectModel;
using Xeml.Manager;

namespace Xeml.Document
{
    /// <summary>
    /// Collections of resources used by the current xeml document.
    /// </summary>
    public class DocumentResources
    {
        #region Fields
        //private IdentifiableObjectDictionary<string, ParameterValidationResource> parameterValidationRessources;
        private ProviderResourceCollection _dataProvider;
        private HandlerResourceCollection _envOntologyHandler;
        private HandlerResourceCollection _genotypeOntologyHandler;
        private HandlerResourceCollection _organismStructureOntologyHandler;
        private HandlerResourceCollection _developmentalOntologyHandler;
        private HandlerResourceCollection _positioningOntologyHandler;

        Dictionary<OntologyType, HandlerResourceCollection> HandlerResourceCollectionOf;
        #endregion

        #region Properties
        private IDocument _xemlDoc;

        /// <summary>
        /// The owning xeml document of these resources
        /// </summary>
        public IDocument XemlDocument
        {
            get { return _xemlDoc; }
            set { _xemlDoc = value; }
        }

        /// <summary>
        /// A collection of data provider ressources.
        /// </summary>
        public ProviderResourceCollection DataProvider
        {
            get
            {
                return this._dataProvider;
            }
        }

        private ReadOnlyCollection<OntologyHandlerResource> _readonlyEnvHandler;
        /// <summary>
        /// A collection of environmental ontology handler.
        /// </summary>
        public ReadOnlyCollection<OntologyHandlerResource> EnvironmentOntologyHandler
        {
            get { return _readonlyEnvHandler; }
        }

        private ReadOnlyCollection<OntologyHandlerResource> _readonlyGermPlasmHandler;
        /// <summary>
        /// A collection of germplasm ontology handler.
        /// </summary>
        public ReadOnlyCollection<OntologyHandlerResource> GermPlasmOntologyHandler
        {
            get { return _readonlyGermPlasmHandler; }
        }

        private ReadOnlyCollection<OntologyHandlerResource> _readonlyStructHandler;
        /// <summary>
        /// A collection of organism structure ontology handler.
        /// </summary>
        public ReadOnlyCollection<OntologyHandlerResource> OrganismStructureOntologyHandler
        {
            get { return this._readonlyStructHandler; }
        }

        private ReadOnlyCollection<OntologyHandlerResource> _readonlyDevHandler;
        /// <summary>
        /// A collection of organism structure ontology handler.
        /// </summary>
        public ReadOnlyCollection<OntologyHandlerResource> DevelopmentalOntologyHandler
        {
            get { return this._readonlyDevHandler; }
        }

        private ReadOnlyCollection<OntologyHandlerResource> _readonlyPosHandler;
        /// <summary>
        /// A collection of organism structure ontology handler.
        /// </summary>
        public ReadOnlyCollection<OntologyHandlerResource> PositioningOntologyHandler
        {
            get { return this._readonlyPosHandler; }
        }
        #endregion

        #region Constructors
        /// <summary>
        /// The standard constructor.
        /// </summary>
        public DocumentResources()
        {
            _dataProvider = new ProviderResourceCollection(this);
            _envOntologyHandler = new HandlerResourceCollection(this);
            _genotypeOntologyHandler = new HandlerResourceCollection(this);
            _organismStructureOntologyHandler = new HandlerResourceCollection(this);
            _developmentalOntologyHandler = new HandlerResourceCollection(this);
            _positioningOntologyHandler = new HandlerResourceCollection(this);

            _readonlyGermPlasmHandler = new ReadOnlyCollection<OntologyHandlerResource>(_genotypeOntologyHandler);
            _readonlyStructHandler = new ReadOnlyCollection<OntologyHandlerResource>(_organismStructureOntologyHandler);
            _readonlyEnvHandler = new ReadOnlyCollection<OntologyHandlerResource>(_envOntologyHandler);
            _readonlyDevHandler = new ReadOnlyCollection<OntologyHandlerResource>(_developmentalOntologyHandler);
            _readonlyPosHandler = new ReadOnlyCollection<OntologyHandlerResource>(_positioningOntologyHandler);

            _dataProvider.CollectionChanged += new EventHandler(OnCollectionChanged);
            _envOntologyHandler.CollectionChanged += new EventHandler(OnCollectionChanged);
            _organismStructureOntologyHandler.CollectionChanged += new EventHandler(OnCollectionChanged);
            _genotypeOntologyHandler.CollectionChanged += new EventHandler(OnCollectionChanged);
            _positioningOntologyHandler.CollectionChanged += new EventHandler(OnCollectionChanged);

            HandlerResourceCollectionOf = new Dictionary<OntologyType, HandlerResourceCollection>()
            {
                { OntologyType.Environment, _envOntologyHandler },
                { OntologyType.Developmental, _developmentalOntologyHandler },
                { OntologyType.Genotype, _genotypeOntologyHandler },
                { OntologyType.OrganismStructure, _organismStructureOntologyHandler },
                { OntologyType.Positioning, _positioningOntologyHandler },
            };
        }
        #endregion

        public void Remove(OntologyHandlerResource ohr)
        {
            ohr.LoadComponent();
            if (ohr.ComponentState == ComponentLoadState.Loaded)
            {
                HandlerResourceCollectionOf[ohr.Handler.OntologyType].Remove(ohr);
                OnHandlerRemoved(ohr);
            }
            else
            {
                if (_envOntologyHandler.Contains(ohr))
                {
                    _envOntologyHandler.Remove(ohr);
                    OnHandlerRemoved(ohr);
                }
                if (_organismStructureOntologyHandler.Contains(ohr))
                {
                    _organismStructureOntologyHandler.Remove(ohr);
                    OnHandlerRemoved(ohr);
                }
                if (_developmentalOntologyHandler.Contains(ohr))
                {
                    _developmentalOntologyHandler.Remove(ohr);
                    OnHandlerRemoved(ohr);
                }
                if (_positioningOntologyHandler.Contains(ohr))
                {
                    _positioningOntologyHandler.Remove(ohr);
                    OnHandlerRemoved(ohr);
                }
                if (_genotypeOntologyHandler.Contains(ohr))
                {
                    _genotypeOntologyHandler.Remove(ohr);
                    OnHandlerRemoved(ohr);
                }
            }
        }

        public OntologyHandlerResource Add(string uri, string alias, string instanceLocation, bool loadableOnly)
        {
            OntologyType ontologyType;
            if (!OntologyManager.Instance.Contains(uri))
            {
                IOntologyHandler ontology = OntologyManager.Instance.CreateHandler(uri, instanceLocation);
                ontologyType = ontology.OntologyType;
            }
            else
            {
                ontologyType = OntologyManager.Instance.Get(uri).OntologyType;
            }

            return Add(uri, alias, instanceLocation, ontologyType, loadableOnly);
        }

        public OntologyHandlerResource Add(string uri, string alias, string instanceLocation, OntologyType ontologyType, bool loadableOnly)
        {
            if (Contains(alias, ontologyType))
            {
                throw new ArgumentException("An ontology handler with the same type and alias already exist.");
            }

            OntologyHandlerResource ohr = new OntologyHandlerResource(uri);

            ohr.NameSpaceAlias = alias;
            ohr.Location = instanceLocation;
            ohr.LoadComponent();

            if (ohr.ComponentState == ComponentLoadState.Loaded || !loadableOnly)
            {
                if (HandlerResourceCollectionOf.ContainsKey(ontologyType))
                {
                    HandlerResourceCollectionOf[ontologyType].Add(ohr);
                    OnHandlerAdded(ohr);
                }
            }

            return ohr;
        }

        public bool Contains(string alias, OntologyType ot)
        {
            return HandlerResourceCollectionOf[ot].Contains(alias);
        }

        internal void Clear()
        {
            foreach (HandlerResourceCollection hrc in HandlerResourceCollectionOf.Values)
            {
                hrc.Clear();
            } 
            _dataProvider.Clear();
            OnHandlerResourcesCleared();
        }

        void OnCollectionChanged(object sender, EventArgs e)
        {
            OnChanged();
        }

        public event EventHandler Changed;
        protected virtual void OnChanged()
        {

            if (Changed != null)
            {
                Changed(this, new EventArgs());
            }
        }

        public event EventHandler<ItemEventArgs<OntologyHandlerResource>> HandlerResourceAdded;
        private void OnHandlerAdded(OntologyHandlerResource ohr)
        {
            if (HandlerResourceAdded != null)
                HandlerResourceAdded(this, new ItemEventArgs<OntologyHandlerResource>(ohr));
        }

        public event EventHandler<ItemEventArgs<OntologyHandlerResource>> HandlerResourceRemoved;
        private void OnHandlerRemoved(OntologyHandlerResource ohr)
        {
            if (HandlerResourceRemoved != null)
                HandlerResourceRemoved(this, new ItemEventArgs<OntologyHandlerResource>(ohr));
        }

        public event EventHandler HandlerResourcesCleared;
        private void OnHandlerResourcesCleared()
        {
            if (HandlerResourcesCleared != null)
                HandlerResourcesCleared(this, new EventArgs());
        }

        
    }
}
